package com.getan.boot.web.web.exception;

import com.getan.boot.common.ResponseCodeData;
import com.getan.boot.common.exception.ApplicationException;
import com.getan.boot.common.exception.ResponseCodeException;
import com.getan.boot.common.holder.trace.TraceContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * Servlet 全局异常处理
 *
 * @author Bruce.Gong
 * @since 1.0.0-SNAPSHOT
 */
@Slf4j
@RestControllerAdvice
public class ApplicationExceptionHandler {

    /**
     * 全局异常处理
     */
    @ExceptionHandler(value = ResponseCodeException.class)
    public ResponseCodeData<?> handlerResponseCodeException(ResponseCodeException e) {
        log.error("ResponseCodeException handler", e);
        if (e.getResponseCode() == null) {
            return wrapperTraceId(new ResponseCodeData<Void>().fail(e.getMessage()));
        } else {
            return wrapperTraceId(new ResponseCodeData<Void>().fail(e.getResponseCode().getCode(), e.getMessage()));
        }
    }

    /**
     * 全局异常处理
     */
    @ExceptionHandler(value = ApplicationException.class)
    public ResponseCodeData<?> handlerGetanException(ApplicationException e) {
        log.error("GetanException handler", e);
        return wrapperTraceId(new ResponseCodeData<Void>().fail(e.getMessage()));
    }

    /**
     * 参数校验异常
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public ResponseCodeData<?> handlerGetanException(MethodArgumentNotValidException e) {
        log.error("MethodArgumentNotValidException handler", e);
        // 只返回第一个校验异常的 message
        FieldError error = e.getFieldErrors().get(0);
        return wrapperTraceId(new ResponseCodeData<Void>().fail(error.getDefaultMessage()));
    }

    /**
     * 全局异常处理
     */
    @ExceptionHandler(value = Exception.class)
    public ResponseCodeData<?> handler(Exception e) {
        log.error("Exception handler", e);
        return wrapperTraceId(new ResponseCodeData<Void>().fail(e.getMessage()));
    }

    private ResponseCodeData<?> wrapperTraceId(ResponseCodeData<?> response) {
        response.setTraceId(TraceContextHolder.getTraceId());
        return response;
    }

}
